package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.IdAndNumDTO;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author lcm
 * @since 2023-07-19
 */
@Service
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    @Autowired
    CourseClient courseClient;
    @Autowired
    CatalogueClient catalogueClient;
    @Autowired
    private LearningLessonMapper learningLessonMapper;
    @Autowired
    private LearningRecordMapper learningRecordMapper;

    @Override
    @Transactional
    public void addUserLessons(Long userId, List<Long> courseIds) {
        //1.查询课程有效期
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
        if (!CollUtils.isNotEmpty(simpleInfoList)) {
            log.error("课程信息不存在,无法添加到课表");
            return;
        }
        //2.循环遍历，处理LearningLesson数据
        ArrayList<LearningLesson> list = new ArrayList<>(simpleInfoList.size());
        for (CourseSimpleInfoDTO courseSimpleInfoDTO : simpleInfoList) {
            LearningLesson learningLesson = new LearningLesson();
            //2.1获取过期时间
            Integer validDuration = courseSimpleInfoDTO.getValidDuration();
            if (validDuration != null && validDuration > 0) {
                learningLesson.setCreateTime(LocalDateTime.now());
                learningLesson.setExpireTime(LocalDateTime.now().plusMonths(validDuration));
            }
            //2.2.填充userId和courseId
            learningLesson.setUserId(userId);
            learningLesson.setCourseId(courseSimpleInfoDTO.getId());
            list.add(learningLesson);
        }
        //3.批量新增
        saveBatch(list);

    }

    @Override
    public void deleteUserLessons(Long userId, List<Long> courseIds) {
        //1.获取用户id
        if (userId == null) {
            userId = UserContext.getUser();
        }
        //2.删除用户的课程信息
        LambdaQueryWrapper<LearningLesson> lqw = new QueryWrapper<LearningLesson>()
                .lambda()
                .eq(LearningLesson::getUserId, userId);
        for (Long courseId : courseIds) {
            lqw.eq(LearningLesson::getCourseId, courseId);
        }
        remove(lqw);


    }

    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery pageQuery) {
        //1.获取当前登录用户
        Long userId = UserContext.getUser();
        //2.分页查询
        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .page(pageQuery.toMpPage("latest_learn_time", false));

        List<LearningLesson> records = page.getRecords();

        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }
        //3.查询课程信息
        //3.1.获取课程id
        Set<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
        //3.2.查询课程信息
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
        if (!CollUtils.isNotEmpty(simpleInfoList)) {
            log.error("课程信息不存在,无法添加到课表");
            throw new BadRequestException("课程信息不存在！");
        }

        //3.3.把课程集合处理成Map集合,key是courseId,value是course对象
        Map<Long, CourseSimpleInfoDTO> courseMap = simpleInfoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, Function.identity()));

        ArrayList<LearningLessonVO> list = new ArrayList<>(records.size());

        //4.封装LearningLessonVO返回
        //4.1.循环遍历将LearningLesson转为VO
        for (LearningLesson record : records) {
            //拷贝数据至VO
            LearningLessonVO learningLessonVO = BeanUtils.copyBean(record, LearningLessonVO.class);
            CourseSimpleInfoDTO courseSimpleInfoDTO = courseMap.get(record.getCourseId());
            learningLessonVO.setCourseName(courseSimpleInfoDTO.getName());
            learningLessonVO.setCourseCoverUrl(courseSimpleInfoDTO.getCoverUrl());
            learningLessonVO.setSections(courseSimpleInfoDTO.getSectionNum());
            list.add(learningLessonVO);
        }

        return PageDTO.of(page, list);
    }

    @Override
    public LearningLessonVO queryNowCourse() {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.根据用户id查询最近学习的课程信息
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (lesson == null) {
            return null;
        }
        //3.拷贝PO到VO中
        LearningLessonVO learningLessonVO = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        //4.查询课程信息
        CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(learningLessonVO.getCourseId(), false, false);
        if (courseInfoById == null) {
            throw new BadRequestException("课程不存在");
        }
        learningLessonVO.setCourseName(courseInfoById.getName());
        learningLessonVO.setCourseCoverUrl(courseInfoById.getCoverUrl());
        learningLessonVO.setSections(courseInfoById.getSectionNum());
        //5.统计课程总数
        Integer count = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .count();
        learningLessonVO.setCourseAmount(count);
        //6.查询最近一次学习的小节序号、查询最近一次学习小节名称
        List<CataSimpleInfoDTO> cInfos = catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getLatestSectionId()));
        if (!CollUtils.isEmpty(cInfos)) {
            CataSimpleInfoDTO cInfo = cInfos.get(0);
            learningLessonVO.setLatestSectionName(cInfo.getName());
            learningLessonVO.setLatestSectionIndex(cInfo.getCIndex());
        }
        return learningLessonVO;
    }

    @Override
    public LearningLessonVO getLessonStatus(Long courseId) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.根据用户id获取课表信息
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        //3.拷贝PO信息到VO并返回
        return BeanUtils.copyBean(lesson, LearningLessonVO.class);
    }

    @Override
    public void deleteCourseById(Long courseId) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.获取课程id对应课程lqw
        //3.删除对应课程
        LambdaQueryWrapper<LearningLesson> lqw = new LambdaQueryWrapper<>();
        lqw.eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId);
        learningLessonMapper.delete(lqw);
    }

    @Override
    public Long isLessonValid(Long courseId) {
        //1.获取用户
        Long userId = UserContext.getUser();
        //2.获取用户的课程信息
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();

        if (lesson == null || lesson.getCourseId() == null) {
            return null;
        }
        //3.查询课程状态
        LessonStatus status = lesson.getStatus();
        if (status == LessonStatus.EXPIRED) {
            return null;
        }
        return lesson.getId();
    }

    @Override
    public Integer countLesson(Long courseId) {
        //1.统计课程人数
        return lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .count();
    }


    @Override
    public void createPlans(LearningPlanDTO learningPlanDTO) {
        //1.获取用户
        Long userId = UserContext.getUser();
        //2.判断用户的对应课程是否存在学习计划
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, learningPlanDTO.getCourseId())
                .one();
        PlanStatus planStatus = lesson.getPlanStatus();
        if(planStatus==PlanStatus.PLAN_RUNNING){
            return;
        }
        //3.修改学习计划状态，存入每周学习频率
        lesson.setPlanStatus(PlanStatus.PLAN_RUNNING);
        lesson.setWeekFreq(learningPlanDTO.getFreq());
        updateById(lesson);
        log.info("创建学习计划结果为：{}",updateById(lesson));
    }

    @Override
    public LearningPlanPageVO showPlans(PageQuery pageQuery) {

        LearningPlanPageVO result = new LearningPlanPageVO();
        //1.获取用户
        Long userId = UserContext.getUser();
        //2.获取用户的学习计划表,满足条件(属于当前用户，有学习计划，在学习中)
        List<LearningLesson> lessons = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .list();
        if (CollUtils.isEmpty(lessons)) {
            return null;
        }
        //2.1 获取本周起始时间
        LocalDate now = LocalDate.now();
        LocalDateTime begin = DateUtils.getWeekBeginTime(now);
        LocalDateTime end = DateUtils.getWeekEndTime(now);
        //3. 查询总的统计数据
        //3.1 本周总的已学习小节数量
        Integer weekFinished = learningRecordMapper.selectCount(new LambdaQueryWrapper<LearningRecord>()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getFinished, true)
                .gt(LearningRecord::getFinishTime, begin)
                .lt(LearningRecord::getFinishTime, end)
        );
        result.setWeekFinished(weekFinished);
        //3.2本周总的计划学习小节数量
        Integer weekTotalPlans = learningLessonMapper.getSumPlan(userId);
        result.setWeekTotalPlan(weekTotalPlans);
        // 4.查询分页数据
        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        // 4.1.分页查询课表信息以及学习计划信息
        List<LearningLesson> records = page.getRecords();
        if(CollUtils.isEmpty(records)){
            return result.emptyPage(page);
        }
        // 4.2.查询课表对应的课程信息
        List<Long> ids = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> infoList = courseClient.getSimpleInfoList(ids);
        Map<Long, CourseSimpleInfoDTO> cMap = infoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, Function.identity()));


        List<IdAndNumDTO> nList = learningRecordMapper.countLearnedSections(userId, begin, end);

        Map<Long, Integer> countMap = IdAndNumDTO.toMap(nList);

        // 4.3.组装数据VO
        List<LearningPlanVO> list=new ArrayList<>(records.size());
        for (LearningLesson record : records) {
            // 4.4.1.拷贝基础属性到vo
            LearningPlanVO learningPlanVO = BeanUtils.copyBean(record, LearningPlanVO.class);
            CourseSimpleInfoDTO courseSimpleInfoDTO = cMap.get(record.getCourseId());
            if(courseSimpleInfoDTO!=null){
                // 4.4.2.填充课程详细信息
                learningPlanVO.setCourseName(courseSimpleInfoDTO.getName());
                learningPlanVO.setSections(courseSimpleInfoDTO.getSectionNum());
            }

            // 4.4.3.每个课程的本周已学习小节数量
            learningPlanVO.setWeekLearnedSections(countMap.getOrDefault(record.getId(), 0));
            list.add(learningPlanVO);
        }

        return result.pageInfo(page.getTotal(),page.getPages(),list);
    }
}
